import { Injectable, NotFoundException, ConflictException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import * as bcrypt from 'bcryptjs';
import { CreateApartmentUserDto } from './dto/create-apartment-user.dto';
import { UpdateApartmentUserDto } from './dto/update-apartment-user.dto';
import { ApartmentUser } from './entities/apartment-user.entity';
import { UserProfileDto } from './dto/user-profile.dto';

@Injectable()
export class ApartmentUserService {
  constructor(
    @InjectRepository(ApartmentUser)
    private readonly apartmentUserRepository: Repository<ApartmentUser>,
  ) {}

  async create(createApartmentUserDto: CreateApartmentUserDto): Promise<UserProfileDto> {
    const { email, password } = createApartmentUserDto;

    // Check if user with this email already exists
    const existingUser = await this.apartmentUserRepository.findOne({ where: { email } });
    if (existingUser) {
      throw new ConflictException('User with this email already exists');
    }

    // Hash the password
    const hashedPassword = await bcrypt.hash(password, 10);

    // Create and save the new user
    const newUser = this.apartmentUserRepository.create({
      ...createApartmentUserDto,
      password: hashedPassword,
    });

    await this.apartmentUserRepository.save(newUser);

    // Return user without password
    const { password: _, ...userWithoutPassword } = newUser;
    return new UserProfileDto(userWithoutPassword);
  }

  async findAll(): Promise<UserProfileDto[]> {
    const users = await this.apartmentUserRepository.find();
    return users.map(user => {
      const { password, ...userWithoutPassword } = user;
      return new UserProfileDto(userWithoutPassword);
    });
  }

  async findOne(id: string): Promise<UserProfileDto> {
    const user = await this.apartmentUserRepository.findOne({ where: { id } });
    
    if (!user) {
      throw new NotFoundException(`User with ID "${id}" not found`);
    }

    const { password, ...userWithoutPassword } = user;
    return new UserProfileDto(userWithoutPassword);
  }

  async findOneByEmail(email: string): Promise<ApartmentUser> {
    const user = await this.apartmentUserRepository.findOne({ where: { email } });
    
    if (!user) {
      throw new NotFoundException(`User with email "${email}" not found`);
    }

    return user;
  }

  async update(id: string, updateApartmentUserDto: UpdateApartmentUserDto): Promise<UserProfileDto> {
    // Check if user exists
    const user = await this.apartmentUserRepository.findOne({ where: { id } });
    
    if (!user) {
      throw new NotFoundException(`User with ID "${id}" not found`);
    }

    // Hash password if it's included in the update
    if (updateApartmentUserDto.password) {
      updateApartmentUserDto.password = await bcrypt.hash(updateApartmentUserDto.password, 10);
    }

    // Update the user
    await this.apartmentUserRepository.update(id, updateApartmentUserDto);
    
    // Fetch the updated user
    const updatedUser = await this.apartmentUserRepository.findOne({ where: { id } });
    
    if (!updatedUser) {
      throw new NotFoundException(`User with ID "${id}" not found after update`);
    }
    
    const { password, ...userWithoutPassword } = updatedUser;
    return new UserProfileDto(userWithoutPassword);
  }

  async remove(id: string): Promise<void> {
    const result = await this.apartmentUserRepository.delete(id);
    
    if (result.affected === 0) {
      throw new NotFoundException(`User with ID "${id}" not found`);
    }
  }
}
